namespace GYLite
{
	/**资源对象，包含资源以及资源的引用计数，引用计数为0时，资源会被回收*/
	export class ResObject implements IResource
	{
		public static id:number=0;
		public type:number;		
		/**资源，如BitmapData，直接调取并不增加应用计数count，不需调用relRes释放，如需增加计数，请调用getRes，释放请调用relRes*/
		public res:any;
		/**资源加载的路径*/
		public pathKey:string;
		/**附属资源*/
		public param:any;
		public inPool:boolean;
		/**生命周期，默认NaN，无周期限制，意味当资源引用数为0时，不会被回收，需要手动回收，或者开启全局的资源回收检测*/
		public lifeTime:number;
		private _bornTime:number;
		private _id:number;
		private _refList:IResource[];
		private _refResObjects:ResObject[];
		private _inWait:boolean;
		private _disposed:boolean;
		public constructor()
		{
			let s = this;			
			s.param = {};
			s._id = ++ResObject.id;
			s._refList = [];
			s._refResObjects = [];
		}
		/**id*/
		public get id():number
		{
			return this._id;
		}
		/**设置关联的引用资源
		 * 例如图集的json，关联引用的0-图片资源
		 * 例如spine资源的json，关联引用的0-atlas图集描述,1-图片资源
		*/
		public setRefResObject(resObjs:ResObject[]):void
		{
			let len:number;
			len = resObjs.length;
			while(--len > -1)			
				resObjs[len].refRes(this);//引用附属资源			
			this._refResObjects = resObjs;
		}
		/**获取关联的引用资源（例如图集json关联引用的图片资源）\
		 * @param index 资源数组的索引
		*/
		public getRefResObject(index:number=0):ResObject
		{
			return this._refResObjects[index];
		}
		// /**(废弃，请更换refRes引用资源)获取资源时，请尽量使用getRes，以便引用计数*/
		// public getRes():any
		// {
		// 	var s = this;
		// 	++s._count;
		// 	return s.res;
		// }
		/**引用资源，refObj对象将持有资源此资源的引用，
		 * 同一个对象只能持同一个资源的一个引用，重复引用将被忽略
		 * 当resObj被销毁，引用也会自动解除，或者调用relRes解除引用
		 * @param resObj 引用资源的对象		 
		 * @param lifeTime 当引用为0时，进入回收队列，设定一个存活周期，默认NaN，不更改当前周期
		 * */
		public refRes(refObj:IResource, lifeTime:number=NaN):any
		{
			var s = this;
			if(s._refList.indexOf(refObj) == -1)
			{
				s._refList[s._refList.length] = refObj;		
				if(lifeTime == lifeTime)
					s.lifeTime = lifeTime;
				s._bornTime = Date.now();
				s.removeFromWait();				
				return s.res;
			}
			SysError.REF_REPEAT_ERROR.throwError([s.pathKey]);					
			return s.res;
		}
		/**资源释放
		 * @param resObj 引用资源的对象
		 * @param lifeTime 当引用数为0时，进入回收队列，设定一个存活周期(毫秒)，默认NaN，不更改当前周期
		*/
		public relRes(refObj:IResource, lifeTime:number=NaN):void
		{
			var s = this;
			var ind:number;
			ind = s._refList.indexOf(refObj);
			if(ind == -1)
			{
				SysError.REL_ERROR.throwError([s.pathKey]);
				return;
			}
			if(lifeTime == lifeTime)
				s.lifeTime = lifeTime;
			s._refList.splice(ind, 1);
			s.checkUse();
		}
		public get disposed():boolean
		{
			return this._disposed;
		}
		public dispose():void
		{
			if(this._disposed)return;
			this._disposed = true;
			GYLoader.deleteRes(this);
		}
		/**请不要直接调用clear回收资源对象，使用dispose走完整的系统销毁流程以便解除GYLoader的引用*/
		public clear(gc:boolean=true):void
		{
			var s = this;
			if(s.inPool)return;
			if(CommonUtil.GYIs(s.res,egret.Texture))
			{
				if (s.res.bitmapData && s.res.bitmapData.source && s.res.bitmapData.source.src) {
					var url = s.res.bitmapData.source.src;
					if (url.indexOf("blob:") == 0) {
						let winURL = window["URL"] || window["webkitURL"];
						try {
							winURL.revokeObjectURL(url);
						}
						catch (e) {
							egret.$warn(1037);
						}
					}
				}
				//存在atlasName，则是合批图集，移除图集
				if(s.param.atlasName)
					AtlasRender.getInstance().removeAtlas(s.param.atlasName);
				//存在合批管理器，移除合批
				if(s.res.$batchManager)
					(<egret.Texture>s.res).$batchManager.dispose();
				if(s.res)
					s.res.dispose();
			}
			if(s.type == LoadType.TYPE_SOUND)
			{
				(<egret.Sound>s.res).close();
			}
			else if(s.type == LoadType.TYPE_FONT)
			{
				if(s.res)
				{
					document.head.removeChild(s.res);
					let winURL = window["URL"] || window["webkitURL"];
					winURL.revokeObjectURL(s.res.dataset.src);					
				}					
			}
			if(s.type == LoadType.TYPE_ATLAS)
			{
				if(s.param)
				{
					let len:number;
					//子图
					len = s.param.subRes.length;
					for(var key in s.param.subRes)
					{
						GYLoader.deleteRes(s.param.subRes[key]);
					}
					s.param.subRes = null;
					//由于动态创建的图集可能回出现同名附加，所以存在同名图集列表
					if(s.param.atlases)
					{
						len = s.param.atlases.length;
						while(--len>-1)						
							GYLoader.deleteRes(s.param.atlases[len]);
						s.param.atlases.length = 0;
					}
				}				
			}
			if(s._refResObjects.length > 0)
			{
				let len:number;
				len = s._refResObjects.length;
				while(--len>-1)
				{
					GYLoader.deleteRes(s._refResObjects[len]);
				}
				s._refResObjects.length = 0;
			}
			s.type = 0;
			s.res = null;			
			s.param = {};
			s._refList.length = 0;			
			ResObject._pool.push(this);
			s.inPool = true;
		}
		/**引用数量*/
		public get count():number
		{
			return this._refList.length;
		}
		/**生产时间*/
		public get bornTime():number
		{
			return this._bornTime;
		}
		/**是否仍然有未销毁的对象使用资源中*/
		public inUse():boolean
		{
			let s = this;
			let len:number;
			len = s._refList.length;
			while(--len>-1)
			{
				if(!s._refList[len].disposed)
					return true;
			}
			return false;
		}
		/**检测是否引用为0且存活周期有限制，进入回收队列*/
		public checkUse():void
		{
			let s= this;
			if(s._refList.length == 0 && s.lifeTime == s.lifeTime)
			{
				if(ResObject._disposeWaitList.indexOf(s) == -1)
				{
					s._inWait = true;
					ResObject._disposeWaitList[ResObject._disposeWaitList.length] = s;
				}					
			}				
		}
		/**从等候销毁队列中移除*/
		private removeFromWait():void
		{
			let s= this;
			if(s._inWait)
			{
				s._inWait = false;
				let ind:number = ResObject._disposeWaitList.indexOf(s);
				ResObject._disposeWaitList.splice(ind, 1);
			}
		}
		
		
		private static _pool:ResObject[];		
		private static _disposeWaitList:ResObject[];
		public static create():ResObject
		{		
			let res:ResObject;	
			if(!ResObject._pool)
			{				
				ResObject._pool=[];
				ResObject._disposeWaitList = [];
				TimeManager.timeInterval(ResObject.disposeInterval, ResObject, 1000);
			}
			if(ResObject._pool.length==0)
				res =  new ResObject();
			else
				res = ResObject._pool.pop();
			res.inPool = false;
			res.lifeTime = NaN;
			res.param = {};
			res._bornTime = Date.now();
			return res;
		}
		/**销毁轮候队列**/
		private static disposeInterval():void
		{
			let len:number;
			let resObj:ResObject;
			let t:number = Date.now();
			len = ResObject._disposeWaitList.length;
			while(--len>-1)
			{
				resObj = ResObject._disposeWaitList[len];				
				if(t - resObj._bornTime > resObj.lifeTime)//超过生命周期回收
				{
					resObj.removeFromWait();
					if(resObj._refList.length == 0)//可能在回收轮候中又重新持有引用了，需要判断一下
						resObj.dispose();
				}
			}
		}
	}
}